/*
 * Copyright 2011 Dominik Pretzsch <dominik.pretzsch at gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.blacksheep.jmoteextract.configuration;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Dominik Pretzsch <dominik.pretzsch at gmail.com>
 */
public class Configuration {
    
    private static Configuration instance;
    
    public  static enum PROP {USER, SERVER, SECURITY}    
    
    private static Properties[] properties = null;    
    private static Object[] propFiles = new Object[] {
        new Object[] { "user.properties", true },
        new Object[] { "server.properties", false },
        new Object[] { "security.properties", false }
    };
    
    private static final String basePropFilePath = "de/blacksheep/jmoteextract/configuration/";
    
    private static final Logger LOGGER =  Logger.getLogger(Configuration.class.getName());
    
    private Configuration() {
        properties = new Properties[PROP.values().length];
        for (PROP prop : PROP.values()) {
            Properties p = new Properties();
            try {
                p.load(getPropertyFileInputStream(prop));
            } catch (IOException ex) {
                LOGGER.log(Level.SEVERE, "IOException", ex);
            }
            properties[prop.ordinal()] = p;
        }
    }
    
    private boolean isExtractable(PROP propFileId) {
        Object[] o = (Object[]) propFiles[propFileId.ordinal()];
        return (Boolean) o[1];
    }
    
    private String getPropertyFilePath(PROP propFileId) {
        return basePropFilePath.concat(getPropertyFileName(propFileId));
    }
    
    private String getPropertyFileName(PROP propFileId) {
        Object[] o  = (Object[]) propFiles[propFileId.ordinal()];
        return (String) o[0];
    }
    
    private Properties getProperties(PROP propFileId) {
        return properties[propFileId.ordinal()];
    }
    
    private File getPropertyFile(PROP propFileId) {
        String parentPath = new File(
                        getClass()
                        .getProtectionDomain()
                        .getCodeSource()
                        .getLocation()
                        .getPath()
                      ).getParent();
        
        String parentUri = new File (parentPath).toURI().toString();
        String propFileP = parentUri.concat(getPropertyFileName(propFileId));
        
        File propFile = null; 
        try {
            URI propFileUri = new URI(propFileP);
            propFile = new File(propFileUri);
        } catch (URISyntaxException ex) {
            // TODO: URISyntaxException
            LOGGER.log(Level.SEVERE, "URISyntaxException", ex);
        }
        
        return propFile;
    }
    
    private boolean propertyFileExists(PROP propFileId) {
        File propFile = getPropertyFile(propFileId);        
        return propFile.exists();
    }
    
    private InputStream getPropertyFileInputStream(PROP propFileId) {
        InputStream in = null;
        try {
            if (propertyFileExists(propFileId)) {
                in = new FileInputStream(getPropertyFile(propFileId));
            } else {
                URL propUrl = getClass().getClassLoader().getResource(getPropertyFilePath(propFileId));
                in = propUrl.openStream();
            }
        } catch (FileNotFoundException ex) {
            // TODO: FileNotFoundException
            LOGGER.log(Level.SEVERE, "FileNotFoundException", ex);
        } catch (IOException ex) {
            // TODO: IOException
            LOGGER.log(Level.SEVERE, "IOException", ex);
        }
        return in;
    }
    
    private FileOutputStream getPropertyFileOutputStream(PROP propFileId) {
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(getPropertyFile(propFileId));
        } catch (FileNotFoundException ex) {
            // TODO: FileNotFoundException
            LOGGER.log(Level.SEVERE, "FileNotFoundException", ex);
        }
        return out;
    }
    
    public static Configuration getInstance() {
        if (instance == null) {
            instance = new Configuration();
        }
        return instance;
    }
    
    public String getProperty(PROP propFileId, String key) {
        Properties p = getProperties(propFileId);
        return p.getProperty(key);
    }
    
    public Boolean getBoolean(PROP propFileId, String key) {
        return Boolean.parseBoolean(getProperty(propFileId, key));
    }
    
    public void setProperty(PROP propFileId, String key, String value) {
        if (isExtractable(propFileId)) {
            try {
                Properties p = getProperties(propFileId);
                p.setProperty(key, value);
                p.store(getPropertyFileOutputStream(propFileId), null);
            } catch (IOException ex) {
                // TODO: IOException
                LOGGER.log(Level.SEVERE, "IOException", ex);
            }
        }
    }
}
